bitkeeper revision 1.164.1.1 (3e9c2ab4o17BMDDDGKKzLPZtAZk7-g)
authoriap10@labyrinth.cl.cam.ac.uk <iap10@labyrinth.cl.cam.ac.uk>
Tue, 15 Apr 2003 15:52:20 +0000 (15:52 +0000)
committeriap10@labyrinth.cl.cam.ac.uk <iap10@labyrinth.cl.cam.ac.uk>
Tue, 15 Apr 2003 15:52:20 +0000 (15:52 +0000)
To allow large initrd's (initial ram disks) for domain0, rearrange the
boot code such that the domain 0 module and its optional initrd module
are copied to safety before the main boot process begins.

At the moment, we're copying it to MAX_DIRECTMAP_ADDRESS, which should
be high enough to prevent any nasty overwritting, even on machines with
4GB ram (large frame table) and lots of network/disk devices. We'll find
out soon enough if this ever isn't the case ;-)

xen/arch/i386/boot/boot.S
xen/common/domain.c
xen/common/kernel.c
xen/include/xeno/sched.h

index 1ef335d0306e47701100a25e41bf8b16fc640168..e8993cd66341415557f674cf9cc98fb538bfbfe0 100644 (file)
@@ -76,9 +76,9 @@ hal_entry:
 #endif
         
 continue_boot_cpu:
-        add     $__PAGE_OFFSET,%ebx
-       push    %ebx /* Multiboot info struct */
-       push    %eax /* Multiboot magic value */
+       add     $__PAGE_OFFSET,%ebx
+        push    %ebx /* Multiboot info struct */
+        push    %eax /* Multiboot magic value */
 
         /* Initialize BSS (no nasty surprises!) */
         mov     $__bss_start-__PAGE_OFFSET,%edi
@@ -87,6 +87,44 @@ continue_boot_cpu:
         xor     %eax,%eax
         rep     stosb
 
+        /* Copy all modules (dom0 + initrd if presetn) to safety, above 48MB */
+        mov     (%esp),%eax
+        cmp     $0x2BADB002,%eax
+        jne     2f                           /* skip if magic no good */
+
+        sub     $__PAGE_OFFSET,%ebx         /* turn back into a physaddr */
+
+       mov     0x14(%ebx),%edi              /* mbi->mods_count */
+        dec     %edi                         /* count-- */
+
+       jb      2f                           /* if num modules was zero !!! */
+
+        mov     0x18(%ebx),%eax              /* mbi->mods_addr */
+
+       mov     (%eax),%ebx                  /* mod[0]->mod_start */
+
+        shl     $4,%edi                      /* count*16 */
+        add     %edi,%eax
+        
+        mov     0x4(%eax),%eax               /* mod[mod_count-1]->end */
+
+        mov     %eax,%ecx
+        sub     %ebx,%ecx                   /* length in byte */
+
+        mov     $(MAX_DIRECTMAP_ADDRESS), %edi
+        add     %ecx, %edi                  /* src + length */
+        
+        shr     $2,%ecx                      /* ecx is length/4 */
+
+1:
+        sub     $4,%eax                      /* eax = src, edi = dst */
+        sub     $4,%edi
+        mov     (%eax),%ebx
+        mov     %ebx,(%edi)
+        loop 1b
+
+2:              
+
         /* Initialize low and high mappings of all memory with 4MB pages */
         mov     $idle0_pg_table-__PAGE_OFFSET,%edi
         mov     $0x1e3,%eax                  /* PRESENT+RW+A+D+4MB+GLOBAL */
index 2102e29ee3d7800f1221da096a4a333d0166b6ca..de563ab965c908babbee600ce3e1f9dea3eff815 100644 (file)
@@ -362,10 +362,11 @@ static unsigned long alloc_page_from_domain(unsigned long * cur_addr,
  * userspace dom0 and final setup is being done by final_setup_guestos.
  */
 int setup_guestos(struct task_struct *p, dom0_newdomain_t *params, 
-                  char *data_start, unsigned long data_len, char *cmdline)
+                  char *phy_data_start, unsigned long data_len, 
+                 char *cmdline, unsigned long initrd_len)
 {
     struct list_head *list_ent;
-    char *src, *dst;
+    char *src, *vsrc, *dst, *data_start;
     int i, dom = p->domain;
     unsigned long phys_l1tab, phys_l2tab;
     unsigned long cur_address, alloc_address;
@@ -382,6 +383,21 @@ int setup_guestos(struct task_struct *p, dom0_newdomain_t *params,
     /* Sanity! */
     if ( p->domain != 0 ) BUG();
 
+    /* This is all a bit grim. We've moved the modules to the "safe"
+     physical memory region above MAP_DIRECTMAP_ADDRESS (48MB). Later
+     in this routeine, we're going to copy it down into the region
+     that's actually been allocated to domain 0. This is highly likely
+     to be overlapping, so we use a forward copy.
+
+     MAP_DIRECTMAP_ADDRESS should be safe. The worst case is a machine
+     with 4GB and lots of network/disk cards that allocate loads of
+     buffers. We'll have to revist this if we ever support PAE (64GB).
+
+ */
+
+
+    data_start = map_domain_mem( (unsigned long) phy_data_start );
+
     if ( strncmp(data_start, "XenoGues", 8) )
     {
         printk("DOM%d: Invalid guest OS image\n", dom);
@@ -532,10 +548,24 @@ int setup_guestos(struct task_struct *p, dom0_newdomain_t *params,
     __cli();
     __write_cr3_counted(pagetable_val(p->mm.pagetable));
 
-    /* Copy the guest OS image. */
-    src = (char *)(data_start + 12);
+    /* Copy the guest OS image. */    
+    src = (char *)(phy_data_start + 12);
+    vsrc= (char *)(data_start + 12); /* data_start invalid after first page*/
     dst = (char *)virt_load_address;
-    while ( src < (data_start+data_len) ) *dst++ = *src++;
+    while ( src < (phy_data_start+data_len) )
+      {
+       *dst++ = *vsrc++;
+       src++;
+
+       if ( (((unsigned long)src) & (PAGE_SIZE-1)) == 0 )
+         {
+           unmap_domain_mem( vsrc-1 );
+           vsrc = map_domain_mem( (unsigned long)src );
+         }
+      }
+    unmap_domain_mem( vsrc );
+
+    printk("copy done\n");
 
     /* Set up start info area. */
     memset(virt_startinfo_address, 0, sizeof(*virt_startinfo_address));
@@ -545,6 +575,15 @@ int setup_guestos(struct task_struct *p, dom0_newdomain_t *params,
     virt_startinfo_address->pt_base = virt_load_address + 
         ((p->tot_pages - 1) << PAGE_SHIFT); 
 
+    if ( initrd_len )
+      {
+       virt_startinfo_address->mod_start = (unsigned long)dst-initrd_len;
+       virt_startinfo_address->mod_len   = initrd_len;
+
+       printk("Initrd len 0x%x, start at 0x%08x\n",
+              virt_startinfo_address->mod_len, virt_startinfo_address->mod_start);
+      }
+
     /* Add virtual network interfaces and point to them in startinfo. */
     while (params->num_vifs-- > 0) {
         net_vif = create_net_vif(dom);
index e329980a529296d8c3173d4bf5f34aad82c86fe7..b2316f550d54a1aae73b7284a9e96bfe1fa9af96 100644 (file)
@@ -170,7 +170,7 @@ void cmain (unsigned long magic, multiboot_info_t *mbi)
     printk("Initialised all memory on a %luMB machine\n",
            max_page >> (20-PAGE_SHIFT));
 
-    init_page_allocator(mod[0].mod_end, MAX_MONITOR_ADDRESS);
+    init_page_allocator(__pa(&_end), MAX_MONITOR_ADDRESS);
  
     /* These things will get done by do_newdomain() for all other tasks. */
     current->shared_info = (void *)get_free_page(GFP_KERNEL);
@@ -191,15 +191,21 @@ void cmain (unsigned long magic, multiboot_info_t *mbi)
 
     new_dom = do_newdomain(0, 0);
     if ( new_dom == NULL ) panic("Error creating domain 0\n");
+
+    /* We're going to setup domain0 using the module(s) that we
+       stashed safely above our MAX_DIRECTMAP_ADDRESS in boot/Boot.S
+
+       The second module, if present, is an initrd ramdisk
+     */
+
     if ( setup_guestos(new_dom, 
                        &dom0_params, 
-                       __va(mod[0].mod_start), 
-                       mod[0].mod_end - mod[0].mod_start, 
-                       __va(mod[0].string))
+                       MAX_DIRECTMAP_ADDRESS, 
+                       mod[mbi->mods_count-1].mod_end - mod[0].mod_start,                            __va(mod[0].string),
+                      (mbi->mods_count==2)?
+                          (mod[1].mod_end - mod[1].mod_start):0)
          != 0 ) panic("Could not set up DOM0 guest OS\n");
 
-    release_bytes_to_allocator(__pa(&_end), mod[0].mod_end);
-
     update_dom_time(new_dom->shared_info);
     wake_up(new_dom);
 
index 147f3c40fd1b393bbd1721a77fb95489a3a5c82b..9ca75fb4de5b2e6b055b08213d9fe26bf3891945 100644 (file)
@@ -202,7 +202,8 @@ extern struct task_struct first_task_struct;
 extern struct task_struct *do_newdomain(unsigned int dom_id, unsigned int cpu);
 extern int setup_guestos(
     struct task_struct *p, dom0_newdomain_t *params,
-    char *data_start, unsigned long data_len, char *cmdline);
+    char *data_start, unsigned long data_len, 
+    char *cmdline, unsigned long initrd_len);
 extern int final_setup_guestos(struct task_struct *p, dom_meminfo_t *);
 
 struct task_struct *find_domain_by_id(unsigned int dom);